Function.prototype.myCall = function(obj, ...argvs){
  const keys = Symbol()
  let val

  obj[keys] = this
 
  val = obj[keys](...argvs)
  delete obj[keys]

  return val
}

Function.prototype.myBind = function(obj, ...argv) {
  const keys = Symbol()
  const len = this.length

  const pro = (...proArgv) => {
    if (proArgv.length < len) {
      // 实参小于形参，继续接收参数
      return (...argvChild) => {
        return pro(...proArgv.concat(argvChild))
      }
    }

    // 接收到足够的参数，执行回调
    let val
    obj[keys] = this
    val = obj[keys](...proArgv)
    delete obj[keys]
    return val
  }

  return pro(...argv)
}

function fn (a, b, c, d) {
  console.log(this.a)
  console.log(`${a}+${b}+${c}+${d}`)
}
const obj = {
  a: 1
}
fn.myCall(obj, 'b值')

const fn1 = fn.myBind(obj, 'bs')
fn1('c', 'd', 'e')

// 测试下 new 之后，如果修改类的原型，实例的原型指向是否会发生改变
function FnA1 () {
  console.log(0)
}
const fna1 = new FnA1()
fna1.name = '张三'

FnA1.prototype.name = '李四'
FnA1.prototype.next = function() {
  console.log('下一个')
}

console.log(fna1.name)
fna1.next()

FnA1.prototype.next = function() {
  console.log('新的下一个')
}

fna1.next()

FnA1.prototype = {
  name: '王五',
  next: function() {
    console.log('更换了一个原型对象')
  }
}
fna1.next()
console.log(FnA1.prototype)
